package com.qqq.commonmessage.service;

import com.qqq.commoncore.utils.VerifyUtil;
import com.qqq.commondomain.constants.MessageConstants;
import com.qqq.commondomain.domain.ResultCode;
import com.qqq.commondomain.exception.ServiceException;
import com.qqq.commonredis.service.RedisService;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.stereotype.Service;

import java.time.LocalDateTime;
import java.time.temporal.ChronoUnit;
import java.util.concurrent.TimeUnit;

/**
 * 验证码服务
 */
@Service
@RefreshScope
public class CaptchaService {

    @Autowired
    private RedisService redisService;

    @Autowired
    private AliSmsService aliSmsService;

    // 每⽇发送次数限制
    @Value("${sms.send-limit:50}")
    private Integer sendLimit;

    // 是否发送，默认不发送使⽤123456验证码
    @Value("${sms.send-message:false}")
    private boolean sendMessage;

    // 过期时间，单位分钟，默认5分钟
    @Value("${sms.code-expiration:5}")
    private Long phoneCodeExpiration;

    /**
     * 发送验证码
     */
    public String sendCode(String phone) {
        // 1、校验是否超过每⽇限制
        if (!VerifyUtil.checkPhone(phone)) {
            throw new ServiceException(ResultCode.ERROR_PHONE_FORMAT);
        }
        String limitCacheKey = MessageConstants.SMS_CODE_TIMES_KEY + phone;
        Integer times = redisService.getCacheObject(limitCacheKey, Integer.class);
        times = times == null ? 0 : times;
        if (times >= sendLimit) {
            throw new ServiceException(ResultCode.SEND_MSG_OVERLIMIT);
        }
        // 2、校验是否在1分钟之内频繁发送
        String cacheKey = MessageConstants.SMS_CODE_KEY + phone;
        String cacheValue = redisService.getCacheObject(cacheKey, String.class);
        long expireTime = redisService.getExpire(cacheKey);
        if (!StringUtils.isEmpty(cacheValue) && expireTime >
                phoneCodeExpiration * 60 - 60) {
            long time = expireTime - (phoneCodeExpiration * 60 - 60);
            throw new ServiceException("操作频繁，请在" + time + "秒之后再试",
                    ResultCode.INVALID_PARA.getCode());
        }
        // 3、⽣成验证码
        String verifyCode = sendMessage ?
                VerifyUtil.generateVerifyCode(MessageConstants.DEFAULT_SMS_LENGTH) :
                MessageConstants.DEFAULT_SMS_CODE;
        if (sendMessage) {
            boolean sendMobile = aliSmsService.sendMobileCode(phone, verifyCode);
            if (!sendMobile) {
                //throw new ServiceException(ResultCode.SEND_MSG_FAILED);
            }
        }
        // 4、将验证码和验证码的发送次数存储到redis
        redisService.setCacheObject(cacheKey, verifyCode,
                phoneCodeExpiration, TimeUnit.MINUTES);
        //5. 限制1天内的短信次数   无法预先设置缓存，只能先读后写
        long seconds = ChronoUnit.SECONDS.between(LocalDateTime.now(),
                LocalDateTime.now().plusDays(1).withHour(0).withMinute(0).withSecond(0).withNano(0));
        redisService.setCacheObject(limitCacheKey, times + 1, seconds, TimeUnit.SECONDS);
        return verifyCode;
    }


    /**
     * 从缓存中获取验证码
     *
     * @param phone
     * @return
     */
    public String getCode(String phone) {
        String cacheKey = MessageConstants.SMS_CODE_KEY + phone;
        return redisService.getCacheObject(cacheKey, String.class);
    }


    /**
     * 从缓存中删除验证码
     *
     * @param phone
     * @return
     */
    public boolean deleteCode(String phone) {
        String cacheKey = MessageConstants.SMS_CODE_KEY + phone;
        return redisService.deleteObject(cacheKey);
    }

    /**
     * 校验手机号与验证码是否匹配
     * @param phone 手机号
     * @param code 验证码
     * @return boolean
     */
    public boolean checkCode(String phone,String code) {
        if(getCode(phone) == null || StringUtils.isEmpty(getCode(phone))) {
            throw new ServiceException(ResultCode.INVALID_CODE);
        }
        return getCode(phone).equals(code);
    }
}
